package cz.semjob.learning.instances.creator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cz.semjob.common.attribute.value.NominalStringAttributeValue;
import cz.semjob.document.AnnotatedDocument;
import cz.semjob.document.annotation.LabeledWords;
import cz.semjob.document.annotation.metadata.AnnotationTypeFactory;
import cz.semjob.document.annotation.metadata.Entity;
import cz.semjob.document.processing.DocumentInstance;
import cz.semjob.document.processing.DocumentSentence;
import cz.semjob.document.processing.DocumentWord;
import cz.semjob.document.util.DocumentUtil;
import cz.semjob.learning.data.TaxonomyLearningException;
import cz.semjob.learning.data.attribute.NumericInstanceAttribute;
import cz.semjob.learning.data.attribute.YesNoNominalInstanceAttribute;
import cz.semjob.learning.instances.LabeledTextInstance;
import cz.semjob.learning.instances.UnlabeledTextInstance;

@Component
public class DomainTextInstanceCreator extends BaseTextInstanceCreator
		implements IConfigurableTextInstanceCreator {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7152569816055863297L;

	private static Logger logger = Logger
			.getLogger(DomainTextInstanceCreator.class);

	public static final String CORRESPONDING_ACTIVITY = "CorrespondingActivity";
	public static final String CORRESPONDING_ACTIVITY_DISTANCE = "CorrespondingActivityDistance";
	public static final String IS_SEPARATOR = "IsSeparator";
	public static final String IS_SEPARATOR_AFTER = "IsSeparatorAfter";

	protected YesNoNominalInstanceAttribute correspondingActivityAttribute = new YesNoNominalInstanceAttribute(
			CORRESPONDING_ACTIVITY);

	protected YesNoNominalInstanceAttribute isSeparatorAttribute = new YesNoNominalInstanceAttribute(
			IS_SEPARATOR);

	protected YesNoNominalInstanceAttribute isSeparatorAfterAttribute = new YesNoNominalInstanceAttribute(
			IS_SEPARATOR_AFTER);

	@Autowired
	private AnnotationTypeFactory annotationTypeFactory;

	public DomainTextInstanceCreator() {
		super();
		// attributesNamesList.remove(SENTENCE_RELATIVE_POSITION);
		// attributesNamesList.remove(TEXT_RELATIVE_POSITION);
		// attributesNamesList.remove(HEAD_GENDER);
		attributesNamesList.add(CORRESPONDING_ACTIVITY_DISTANCE);
		// attributesNamesList.add(IS_SEPARATOR);
		// attributesNamesList.add(IS_SEPARATOR_AFTER);
		// attributesNamesList.remove(IS_ITEM);

	}

	public void initTextInstanceCreator() {
		super.initTextInstanceCreator();
		attributesMap.put(CORRESPONDING_ACTIVITY,
				correspondingActivityAttribute);
		attributesMap.put(CORRESPONDING_ACTIVITY_DISTANCE,
				new NumericInstanceAttribute(CORRESPONDING_ACTIVITY_DISTANCE));
		attributesMap.put(IS_SEPARATOR, isSeparatorAttribute);
		attributesMap.put(IS_SEPARATOR_AFTER, isSeparatorAfterAttribute);
		updateAttributes(attributesNamesList);
	}

	public void setMaxInstanceWordLength(int length) {
		MAX_WORDS = length;

	}

	public List<String> getDataSourcesNames() {
		return Arrays.asList("Activity");
	}

	public void setAttributesList(List<String> attributeNames) {
		updateAttributes(attributeNames);
	}

	protected LabeledTextInstance createOneLabeledInstance(
			AnnotatedDocument annotatedDocument, Entity entity,
			boolean positive, List<DocumentWord> words, Object... dataSources)
			throws TaxonomyLearningException {
		LabeledTextInstance labeledTextInstance = super
				.createOneLabeledInstance(annotatedDocument, entity, positive,
						words);
		List<List<DocumentWord>> activityAnnotations = new ArrayList<List<DocumentWord>>();
		activityAnnotations = annotatedDocument
				.getPositiveAnnotations(annotationTypeFactory
						.getEntity("Activity"));
		// }
		createDomainAttributes(activityAnnotations, words, labeledTextInstance);
		return labeledTextInstance;
	}

	private void createDomainAttributes(
			List<List<DocumentWord>> activityAnnotations,
			List<DocumentWord> words, UnlabeledTextInstance labeledTextInstance)
			throws TaxonomyLearningException {

		if (attributesNamesList.contains(CORRESPONDING_ACTIVITY_DISTANCE)) {
			labeledTextInstance
					.addAttributeValue(
							CORRESPONDING_ACTIVITY_DISTANCE,
							getCorrenpondingActivityDistance(words,
									activityAnnotations));
		}
		if (attributesNamesList.contains(IS_SEPARATOR)) {
			if (checkSeparator(labeledTextInstance.getWords())) {
				labeledTextInstance.addAttributeValue(IS_SEPARATOR,
						new NominalStringAttributeValue(IS_SEPARATOR, "yes",
								isSeparatorAttribute));
			} else {
				labeledTextInstance.addAttributeValue(IS_SEPARATOR,
						new NominalStringAttributeValue(IS_SEPARATOR, "no",
								isSeparatorAttribute));
			}
		}
		if (attributesNamesList.contains(IS_SEPARATOR_AFTER)) {
			if (checkSeparatorAfter(labeledTextInstance.getWords())) {
				labeledTextInstance.addAttributeValue(IS_SEPARATOR_AFTER,
						new NominalStringAttributeValue(IS_SEPARATOR_AFTER,
								"yes", isSeparatorAfterAttribute));
			} else {
				labeledTextInstance.addAttributeValue(IS_SEPARATOR_AFTER,
						new NominalStringAttributeValue(IS_SEPARATOR_AFTER,
								"no", isSeparatorAfterAttribute));
			}
		}
	}

	private boolean checkSeparator(List<DocumentWord> words) {
		DocumentSentence sentence = words.get(0).getSentence();
		int minSentenceIndex = sentence.getWordsCount();
		for (DocumentWord documentWord : words) {
			if (documentWord.getSentenceIndex() < minSentenceIndex) {
				minSentenceIndex = documentWord.getSentenceIndex();
			}
		}
		if (minSentenceIndex > 0) {
			DocumentWord previousWord = sentence.getWord(minSentenceIndex - 1);
			if (previousWord.getText().equals("(")
					|| previousWord.getText().equals(",")
					|| previousWord.getText().equals("a")
					|| previousWord.getText().equals("/")
					|| previousWord.getText().equals("nebo")) {
				return true;
			}
		}
		return false;
	}

	protected int getCorrenpondingActivityDistance(List<DocumentWord> words,
			List<List<DocumentWord>> activityAnnotations) {
		DocumentSentence annotationSentence = getAnnotationSentence(words);

		for (List<DocumentWord> activityAnnotation : activityAnnotations) {
			DocumentSentence activitySentecne = getAnnotationSentence(activityAnnotation);
			if (annotationSentence.equals(activitySentecne)) {
				// now check, if activity is related to our annotation
				// check only first word of each annotation
				return getDependentAnnotationsDistance(activityAnnotation,
						words);
			}

		}
		return -1;
	}

	protected UnlabeledTextInstance createOneUnlabeledInstance(
			DocumentInstance documentInstance, List<DocumentWord> pathWords,
			Object... dataSources) throws TaxonomyLearningException {
		UnlabeledTextInstance unlabeledTextInstance = super
				.createOneUnlabeledInstance(documentInstance, pathWords);
		Map<DocumentInstance, List<LabeledWords>> activityInstances = (Map<DocumentInstance, List<LabeledWords>>) dataSources[0];

		List<LabeledWords> activityAnnotations = activityInstances
				.get(documentInstance);

		createDomainAttributes(
				DocumentUtil.convertLabeledWordsList(activityAnnotations),
				pathWords, unlabeledTextInstance);

		return unlabeledTextInstance;
	}

	private boolean checkSeparatorAfter(List<DocumentWord> words) {
		DocumentSentence sentence = words.get(0).getSentence();
		int maxSentenceIndex = 0;
		for (DocumentWord documentWord : words) {
			if (documentWord.getSentenceIndex() > maxSentenceIndex) {
				maxSentenceIndex = documentWord.getSentenceIndex();
			}
		}
		if (maxSentenceIndex < sentence.getWordsCount() - 1) {
			DocumentWord nextWord = sentence.getWord(maxSentenceIndex + 1);
			if (nextWord.getText().equals(")")
					|| nextWord.getText().equals(",")
					|| nextWord.getText().equals("a")
					|| nextWord.getText().equals("/")
					|| nextWord.getText().equals("nebo")) {
				return true;
			}
		}
		return false;
	}

	public String getName() {
		return "Domain";
	}

}
